﻿//===========================================================================================================================
// Cuberry - http://www.cuberry.net
// Copyright (c) 2012
// by Peacequare® - Amir Moussa
//===========================================================================================================================
// This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License 
// as published by the Free Software Foundation, either version 3 of the License, or any later version.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation 
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and 
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions 
// of the Software.
//
// This program is distributed in the hope that it will be useful.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 
// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
// DEALINGS IN THE SOFTWARE.
//
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//===========================================================================================================================

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using P2.Cuberry.Framework.Helper.DAL;


namespace P2.Cuberry.Framework.Helper
{
    public enum P2ValidationStatus { red, yellow, green, white }


    public class P2ValidationItem
    {
        public P2ValidationStatus ValidationType { get; set; }
        public string ClassName { get; set; }
        
        public virtual P2MessageStack Validate(object objectToValidate)
        {
            return new P2MessageStack();
        }

        public virtual void StoreOriginalValues(object objectToValidate)
        {
            
        }
    }


    public class P2ValidationItemProperty : P2ValidationItem
    {
        public string PropertyName { get; set; }
        public bool Mandatory { get; set; }

        protected virtual object GetPropertyValue(object valueObject)
        {
            Type objType = valueObject.GetType();
            return objType.InvokeMember(this.PropertyName, System.Reflection.BindingFlags.GetProperty, null, valueObject, null);
        }
    }


    public class P2ValidationItemInteger : P2ValidationItemProperty
    {
        public int MinValue { get; set; }
        public int MaxValue { get; set; }

        public override P2MessageStack Validate(object objectToValidate)
        {
            try
            {
                P2MessageStack messageStack = base.Validate(objectToValidate);
                object objValue = GetPropertyValue(objectToValidate);
                int value = 0;
                if (objValue == null && this.Mandatory)
                {
                    messageStack.Add(new P2TransactionMessage(P2ValidationStatus.red, P2Translator.GetResource("Validation_NotOK_MissingMandatoryField")));
                    return messageStack;
                }
                else
                {
                    if (objValue is int?)

                        value = ((int?)objValue).GetValueOrDefault(0);
                    else
                        if (objValue is int)
                            value = (int)objValue;
                        else
                            if (objValue is string)
                            {
                                if (!int.TryParse(((string)objValue), out value))
                                {
                                    messageStack.Add(new P2TransactionMessage(P2ValidationStatus.red, P2Translator.GetResource("Validation_NotOK_CheckTypeInt")));
                                    return messageStack;
                                }
                            }
                            else
                            {
                                if (!int.TryParse((objValue.ToString()), out value))
                                {
                                    messageStack.Add(new P2TransactionMessage(P2ValidationStatus.red, P2Translator.GetResource("Validation_NotOK_CheckTypeInt")));
                                    return messageStack;
                                }
                            }
                }

                if (value < this.MinValue || value > this.MaxValue)
                {
                    messageStack.Add(new P2TransactionMessage(this.ValidationType, P2Translator.GetResource("Validation_NotOK_CheckLength")));
                }

                return messageStack;
            }
            catch (System.Exception ex) //AM:TC
            {
                P2ExceptionHandler.LogException(ex, string.Format("{0}.{1}", this.GetType().Name, System.Reflection.MethodInfo.GetCurrentMethod().Name));
                return null;
            }
        }
    }


    public class P2ValidationItemDouble : P2ValidationItemProperty
    {
        public double MinValue { get; set; }
        public double MaxValue { get; set; }

        public override P2MessageStack Validate(object objectToValidate)
        {
            try
            {
                P2MessageStack messageStack = base.Validate(objectToValidate);
                object objValue = GetPropertyValue(objectToValidate);
                double value = 0;
                if (objValue == null && this.Mandatory)
                {
                    messageStack.Add(new P2TransactionMessage(P2ValidationStatus.red, P2Translator.GetResource("Validation_NotOK_MissingMandatoryField")));
                    return messageStack;
                }
                else
                {
                    if (objValue is double?)

                        value = ((double?)objValue).GetValueOrDefault(0);
                    else
                        if (objValue is double)
                            value = (double)objValue;
                        else
                            if (objValue is string)
                            {
                                if (!double.TryParse(((string)objValue), out value))
                                {
                                    messageStack.Add(new P2TransactionMessage(P2ValidationStatus.red, P2Translator.GetResource("Validation_NotOK_CheckTypeDouble")));
                                    return messageStack;
                                }
                            }
                            else
                            {
                                messageStack.Add(new P2TransactionMessage(P2ValidationStatus.red, P2Translator.GetResource("Validation_NotOK_CheckTypeDouble")));
                                return messageStack;
                            }

                }
                if (value < this.MinValue || value > this.MaxValue)
                {
                    messageStack.Add(new P2TransactionMessage(this.ValidationType, P2Translator.GetResource("Validation_NotOK_CheckLength")));
                }

                return messageStack;
            }
            catch (System.Exception ex) //AM:TC
            {
                P2ExceptionHandler.LogException(ex, string.Format("{0}.{1}", this.GetType().Name, System.Reflection.MethodInfo.GetCurrentMethod().Name));
                return null;
            }
        }
    }


    public class P2ValidationItemDateTime : P2ValidationItemProperty
    {
        public DateTime MinValue { get; set; }
        public DateTime MaxValue { get; set; }

        public override P2MessageStack Validate(object objectToValidate)
        {
            try
            {
                P2MessageStack messageStack = base.Validate(objectToValidate);
                object objValue = GetPropertyValue(objectToValidate);
                DateTime value = DateTime.MinValue;
                if (objValue == null && this.Mandatory)
                {
                    messageStack.Add(new P2TransactionMessage(P2ValidationStatus.red, P2Translator.GetResource("Validation_NotOK_MissingMandatoryField")));
                    return messageStack;
                }
                else
                {

                    if (objValue is DateTime?)

                        value = ((DateTime?)objValue).GetValueOrDefault(DateTime.MinValue);
                    else
                        if (objValue is DateTime)
                            value = (DateTime)objValue;
                        else
                            if (objValue is string)
                            {
                                if (!DateTime.TryParse(((string)objValue), out value))
                                {
                                    messageStack.Add(new P2TransactionMessage(P2ValidationStatus.red, P2Translator.GetResource("Validation_NotOK_CheckTypeDateTime")));
                                    return messageStack;
                                }
                            }
                            else
                            {
                                messageStack.Add(new P2TransactionMessage(P2ValidationStatus.red, P2Translator.GetResource("Validation_NotOK_CheckTypeDateTime")));
                                return messageStack;
                            }
                }
                if (value < this.MinValue || value > this.MaxValue)
                {
                    messageStack.Add(new P2TransactionMessage(this.ValidationType, P2Translator.GetResource("Validation_NotOK_CheckLength")));
                }

                return messageStack;
            }
            catch (System.Exception ex) //AM:TC
            {
                P2ExceptionHandler.LogException(ex, string.Format("{0}.{1}", this.GetType().Name, System.Reflection.MethodInfo.GetCurrentMethod().Name));
                return null;
            }
        }
    }


    public class P2ValidationItemDecimal : P2ValidationItemProperty
    {
        public decimal MinValue { get; set; }
        public decimal MaxValue { get; set; }
        public bool NonZero { get; set; }

        public override P2MessageStack Validate(object objectToValidate)
        {
            try
            {
                P2MessageStack messageStack = base.Validate(objectToValidate);
                object objValue = GetPropertyValue(objectToValidate);
                decimal value = 0;
                if (objValue == null && this.Mandatory)
                {
                    messageStack.Add(new P2TransactionMessage(P2ValidationStatus.red, P2Translator.GetResource("Validation_NotOK_MissingMandatoryField")));
                    return messageStack;
                }
                else
                {
                    if (objValue is decimal?)

                        value = ((decimal?)objValue).GetValueOrDefault(0);
                    else
                        if (objValue is decimal)
                            value = (decimal)objValue;
                        else
                            if (objValue is string)
                            {
                                if (!decimal.TryParse(((string)objValue), out value))
                                {
                                    messageStack.Add(new P2TransactionMessage(P2ValidationStatus.red, P2Translator.GetResource("Validation_NotOK_CheckTypeDouble")));
                                    return messageStack;
                                }
                            }
                            else
                            {
                                messageStack.Add(new P2TransactionMessage(P2ValidationStatus.red, P2Translator.GetResource("Validation_NotOK_CheckTypeDouble")));
                                return messageStack;
                            }
                }
                if (this.NonZero && value == 0M)
                {
                    messageStack.Add(new P2TransactionMessage(this.ValidationType, P2Translator.GetResource("Validation_NotOK_CheckZero")));
                }
                if (value < this.MinValue || value > this.MaxValue)
                {
                    messageStack.Add(new P2TransactionMessage(this.ValidationType, P2Translator.GetResource("Validation_NotOK_CheckLength")));
                }
                return messageStack;
            }
            catch (System.Exception ex) //AM:TC
            {
                P2ExceptionHandler.LogException(ex, string.Format("{0}.{1}", this.GetType().Name, System.Reflection.MethodInfo.GetCurrentMethod().Name));
                return null;
            }
        }
    }


    public class P2ValidationItemString : P2ValidationItemProperty
    {
        public int MinLength { get; set; }
        public int MaxLength { get; set; }
        public string RegExTest { get; set; }

        public override P2MessageStack Validate(object objectToValidate)
        {
            try
            {
                P2MessageStack messageStack = base.Validate(objectToValidate);
                object objValue = GetPropertyValue(objectToValidate);
                string value = null;
                if (objValue == null && this.Mandatory)
                {
                    messageStack.Add(new P2TransactionMessage(P2ValidationStatus.red, P2Translator.GetResource("Validation_NotOK_MissingMandatoryField")));
                    return messageStack;
                }
                else
                {
                    if (objValue is string)
                        value = (string)objValue;
                    else
                        value = objValue.ToString();

                }
                if (string.IsNullOrEmpty(value) && this.Mandatory)
                {
                    messageStack.Add(new P2TransactionMessage(P2ValidationStatus.red, P2Translator.GetResource("Validation_NotOK_MissingMandatoryField")));

                }
                else
                {
                    if (value.Length < this.MinLength || value.Length > this.MaxLength)
                    {
                        messageStack.Add(new P2TransactionMessage(this.ValidationType, P2Translator.GetResource("Validation_NotOK_CheckLength")));
                    }
                    if (!string.IsNullOrEmpty(this.RegExTest))
                    {
                        try
                        {
                            System.Text.RegularExpressions.Regex rx = new System.Text.RegularExpressions.Regex(this.RegExTest);
                            if (!rx.IsMatch(value))
                            {
                                messageStack.Add(new P2TransactionMessage(this.ValidationType, P2Translator.GetResource("Validation_NotOK_RegEx")));
                            }
                        }
                        catch (ArgumentException)
                        {
                            messageStack.Add(new P2TransactionMessage(P2ValidationStatus.red, P2Translator.GetResource("Validation_NotOK_RegEx")));
                        }
                    }
                }
                return messageStack;
            }
            catch (System.Exception ex) //AM:TC
            {
                P2ExceptionHandler.LogException(ex, string.Format("{0}.{1}", this.GetType().Name, System.Reflection.MethodInfo.GetCurrentMethod().Name));
                return null;
            }
        }
    }


    public class P2ValidationItemCompare : P2ValidationItem
    {
        public string PropertyName1 { get; set; }
        public string PropertyName2 { get; set; }
        public enum Operations { Equal, NotEqual, GreaterThan, LowerThan, GreaterOrEqual, LowerOrEqual }
        public Operations Operation { get; set; }

        public override P2MessageStack Validate(object objectToValidate)
        {
            try
            {
                P2MessageStack messageStack = new P2MessageStack();
                Type objType = objectToValidate.GetType();
                object objValue1 = objType.InvokeMember(this.PropertyName1, System.Reflection.BindingFlags.GetProperty, null, objectToValidate, null);
                object objValue2 = objType.InvokeMember(this.PropertyName2, System.Reflection.BindingFlags.GetProperty, null, objectToValidate, null);
                if (objValue1.GetType().ToString() != objValue2.GetType().ToString())
                {
                    messageStack.Add(new P2TransactionMessage(P2ValidationStatus.red, P2Translator.GetResource("Validation_NotOK_FieldsAreNotEqual")));
                    return messageStack;
                }
                switch (this.Operation)
                {
                    case Operations.Equal:

                        switch (objValue1.GetType().ToString())
                        {
                            case "System.Decimal":
                                if (((decimal)objValue1) != ((decimal)objValue2))
                                {
                                    messageStack.Add(new P2TransactionMessage(this.ValidationType, P2Translator.GetResource("Validation_NotOK_FieldsAreNotEqual")));
                                }
                                break;
                            case "System.Int32":
                                if (((int)objValue1) != ((int)objValue2))
                                {
                                    messageStack.Add(new P2TransactionMessage(this.ValidationType, P2Translator.GetResource("Validation_NotOK_FieldsAreNotEqual")));
                                }
                                break;
                            case "System.Double":
                                if (((double)objValue1) != ((double)objValue2))
                                {
                                    messageStack.Add(new P2TransactionMessage(this.ValidationType, P2Translator.GetResource("Validation_NotOK_FieldsAreNotEqual")));
                                }
                                break;
                            case "System.String":
                                if (((string)objValue1) != ((string)objValue2))
                                {
                                    messageStack.Add(new P2TransactionMessage(this.ValidationType, P2Translator.GetResource("Validation_NotOK_FieldsAreNotEqual")));
                                }
                                break;
                            case "System.DateTime":
                                if (((DateTime)objValue1) != ((DateTime)objValue2))
                                {
                                    messageStack.Add(new P2TransactionMessage(this.ValidationType, P2Translator.GetResource("Validation_NotOK_FieldsAreNotEqual")));
                                }
                                break;
                            default:
                                if ((objValue1.ToString()) != (objValue2.ToString()))
                                {
                                    messageStack.Add(new P2TransactionMessage(this.ValidationType, P2Translator.GetResource("Validation_NotOK_FieldsAreNotEqual")));
                                }
                                break;
                        }
                        break;
                    case Operations.NotEqual:

                        switch (objValue1.GetType().ToString())
                        {
                            case "System.Decimal":
                                if (((decimal)objValue1) == ((decimal)objValue2))
                                {
                                    messageStack.Add(new P2TransactionMessage(this.ValidationType, P2Translator.GetResource("Validation_NotOK_FieldsAreEqual")));
                                }
                                break;
                            case "System.Int32":
                                if (((int)objValue1) == ((int)objValue2))
                                {
                                    messageStack.Add(new P2TransactionMessage(this.ValidationType, P2Translator.GetResource("Validation_NotOK_FieldsAreEqual")));
                                }
                                break;
                            case "System.Double":
                                if (((double)objValue1) == ((double)objValue2))
                                {
                                    messageStack.Add(new P2TransactionMessage(this.ValidationType, P2Translator.GetResource("Validation_NotOK_FieldsAreEqual")));
                                }
                                break;
                            case "System.String":
                                if (((string)objValue1) == ((string)objValue2))
                                {
                                    messageStack.Add(new P2TransactionMessage(this.ValidationType, P2Translator.GetResource("Validation_NotOK_FieldsAreEqual")));
                                }
                                break;
                            case "System.DateTime":
                                if (((DateTime)objValue1) == ((DateTime)objValue2))
                                {
                                    messageStack.Add(new P2TransactionMessage(this.ValidationType, P2Translator.GetResource("Validation_NotOK_FieldsAreEqual")));
                                }
                                break;
                            default:
                                if ((objValue1.ToString()) == (objValue2.ToString()))
                                {
                                    messageStack.Add(new P2TransactionMessage(this.ValidationType, P2Translator.GetResource("Validation_NotOK_FieldsAreEqual")));
                                }
                                break;
                        }
                        break;

                }
                return messageStack;
            }
            catch (System.Exception ex) //AM:TC
            {
                P2ExceptionHandler.LogException(ex, string.Format("{0}.{1}", this.GetType().Name, System.Reflection.MethodInfo.GetCurrentMethod().Name));
                return null;
            }
        }

    }


    public class P2ValidationItemUnique : P2ValidationItem
    {
        public List<string> PropertyNames { get; set; }
        public string KeyProperty { get; set; }
        public Dictionary<string,string> OriginalPropertyValues { get; set; }


        public override P2MessageStack Validate(object objectToValidate)
        {
            try
            {
                P2MessageStack messageStack = new P2MessageStack();
                Type objType = objectToValidate.GetType();
                string connectionString = Configuration.ConfigurationSetUp.GetConnectionString("Business"); 
                

                if (OriginalPropertyValues == null) OriginalPropertyValues = new Dictionary<string, string>();
                                

                //using (SqlConnection con = new SqlConnection(db.Connection.ConnectionString))
                using (SqlConnection con = new SqlConnection(connectionString))
                {
                    SqlCommand cmd = new SqlCommand();
                    cmd.Connection = con;
                    cmd.CommandType = CommandType.Text;
                    string commandText = string.Format("select count(*) from {0} where 1=1 ", this.ClassName);
                    int paramNum = 0;
                    bool changed = false;
                    foreach (var propertyName in this.PropertyNames)
                    {
                        object objValue = objType.InvokeMember(propertyName, System.Reflection.BindingFlags.GetProperty, null, objectToValidate, null);

                        if (objValue != null)
                        {
                            paramNum++;
                            commandText += string.Format(" and {0} = @P{1} ", propertyName, paramNum.ToString());

                            cmd.Parameters.AddWithValue(string.Format("@P{0} ", paramNum.ToString()), objValue);
                            if (OriginalPropertyValues.ContainsKey(propertyName) && OriginalPropertyValues[propertyName] != objValue.ToString())
                            {
                                changed = true;
                            }
                        }
                        else
                        {
                            if (OriginalPropertyValues.ContainsKey(propertyName) && OriginalPropertyValues[propertyName] != "")
                            {
                                changed = true;
                            }
                        }

                        if (!OriginalPropertyValues.ContainsKey(propertyName))
                            changed = true;
                    }

                    if (!string.IsNullOrEmpty(KeyProperty))
                    {
                        object keyValue = objType.InvokeMember(this.KeyProperty, System.Reflection.BindingFlags.GetProperty, null, objectToValidate, null);
                        if (keyValue != null && keyValue.ToString() != "" && keyValue.ToString() != "-1")
                        {
                            paramNum++;
                            commandText += string.Format(" and {0} != @P{1} ", KeyProperty, paramNum.ToString());
                            cmd.Parameters.AddWithValue(string.Format("@P{0} ", paramNum.ToString()), keyValue);
                        }
                    }
                    else
                    {
                        changed = true;
                    }
                    cmd.CommandText = commandText;
                    con.Open();
                    int numRows = (int)cmd.ExecuteScalar();

                    if (changed && numRows > 0)
                        messageStack.Add(new P2TransactionMessage(this.ValidationType, P2Translator.GetResource("Validation_NotOK_Doublicate")));
                }
                return messageStack;
            }
            catch (System.Exception ex) //AM:TC
            {
                P2ExceptionHandler.LogException(ex, string.Format("{0}.{1}", this.GetType().Name, System.Reflection.MethodInfo.GetCurrentMethod().Name));
                return null;
            }
        }


        public override void StoreOriginalValues(object objectToValidate)
        {
            try
            {
                if (objectToValidate != null)
                {
                    Type objType = objectToValidate.GetType();
                    OriginalPropertyValues = new Dictionary<string, string>();
                    foreach (var propertyName in this.PropertyNames)
                    {
                        object objValue = objType.InvokeMember(propertyName, System.Reflection.BindingFlags.GetProperty, null, objectToValidate, null);

                        if (objValue != null)
                        {
                            OriginalPropertyValues[propertyName] = objValue.ToString();
                        }
                        else
                        {
                            OriginalPropertyValues[propertyName] = "";
                        }
                    }
                }
            }
            catch (System.Exception ex) //AM:TC
            {
                P2ExceptionHandler.LogException(ex, string.Format("{0}.{1}", this.GetType().Name, System.Reflection.MethodInfo.GetCurrentMethod().Name));
            }

        }


    }
}
